package com.dwusoft.banks.tradeBank.common.utils;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.SocketException;
import java.util.Iterator;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.dwusoft.banks.controller.NotifyController;
import com.dwusoft.banks.tradeBank.exception.ErrorConst;
import com.dwusoft.banks.tradeBank.exception.P2PException;

/**
 * @author yzj
 */
public class FtpUtil
{
	public final int ASCII_FILE_TYPE = FTP.ASCII_FILE_TYPE;
	public final int BINARY_FILE_TYPE = FTP.BINARY_FILE_TYPE;

	public FTPClient client;
	protected String config;
	
	private final static Logger logger = LoggerFactory.getLogger(NotifyController.class);

	// 构造函数
	public FtpUtil(String connectionString)
	{
		this.config = connectionString;
	}

	/**
	 * 上传多个文件到指定目录
	 * 
	 * @param filePath
	 * @param files
	 * @return
	 */
	public boolean uploadFiles(File[] files)
	{
		for (File file : files)
		{
			if (uploadFile(this.client, file.getName(), file) == false)
			{
				return false;
			}
		}

		return true;
	}

	/**
	 * 上传多个文件到指定目录
	 * 
	 * @param filePath
	 * @param files
	 * @return
	 */
	public boolean uploadFiles(FTPClient ftpClient, File[] files)
	{
		for (File file : files)
		{
			if (uploadFile(ftpClient, file.getName(), file) == false)
			{
				return false;
			}
		}

		return true;
	}

	/**
	 * @param filePath
	 * @param files
	 * @return
	 */
	public boolean storeFiles(String targetDirectory, Map<String, File> files)
	{
		FTPClient client = connectServer();
		String destPath = targetDirectory;
		boolean flag = true;
		try
		{
			if (!client.changeWorkingDirectory(destPath))
			{
				makeDirectory(client, destPath);
			}
			client.changeWorkingDirectory(destPath);
			for (Iterator<Map.Entry<String, File>> iterator = files.entrySet().iterator(); iterator.hasNext();)
			{
				Map.Entry<String, File> me = iterator.next();
				uploadFile(client, me.getKey(), me.getValue());
			}
		}
		catch (IOException e)
		{
			flag = false;
			logger.error(e.getMessage(), e);
		}
		finally
		{
			closeConnect(client);
		}
		return flag;
	}

	/**
	 * 上传单个文件
	 * 
	 * @param client
	 * @param file
	 * @return
	 */
	public boolean uploadFile(FTPClient client, String fileName, File file)
	{
		boolean flag = false;
		if (client == null)
		{
			return false;
		}

		FileInputStream inputStream = null;
		try
		{
			inputStream = new FileInputStream(file);
			flag = client.storeFile(fileName, inputStream);
			logger.info(fileName + ":upload File" + (flag == true ? "success" : "failed"));
		}
		catch (IOException e)
		{
			flag = false;
			logger.error(fileName + ":upload File false" + e.getMessage(), e);
		}
		finally
		{
			if (inputStream != null)
			{
				try
				{
					inputStream.close();
				}
				catch (IOException e)
				{
					logger.error(e.getMessage(), e);
				}
			}
		}

		return flag;
	}

	/**
	 * 上传单个文件
	 * 
	 * @param client
	 * @param file
	 * @return
	 */
	public boolean uploadFile(String filePath, File file)
	{
		boolean flag = true;
		FileInputStream inputStream = null;
		FTPClient client = null;
		try
		{
			client = connectServer();
			flag = makeDirectory(client, filePath);
			inputStream = new FileInputStream(file);
			flag = client.storeFile(filePath + "/" + file.getName(), inputStream);
			logger.info(file.getName() + ":upload File success");
		}
		catch (IOException e)
		{
			flag = false;
			logger.error(file.getName() + ":upload File false" + e.getMessage(), e);
		}
		finally
		{
			if (inputStream != null)
			{
				try
				{
					inputStream.close();
				}
				catch (IOException e)
				{
					e.printStackTrace();
					throw new P2PException(e.getMessage());
				}
			}
			closeConnect(client);
		}
		return flag;
	}

	/**
	 * @param remoteFileName
	 * @param localName
	 * @return
	 */
	public boolean retrieveFile(String remoteFileName, String localName)
	{
		boolean returnResult = false;

		FTPClient client = connectServer();
		OutputStream output = null;
		try
		{
			output = new FileOutputStream(localName);
			returnResult = client.retrieveFile(remoteFileName, output);
			if (returnResult)
			{
				logger.info("download success");
			}
			else
			{
				logger.error("download failed");
			}
		}
		catch (FileNotFoundException e)
		{
			logger.error("local file not found." + e.getMessage());
			throw new P2PException(ErrorConst.P2P_S0008);
		}
		catch (IOException e)
		{
			logger.error("Could get file from server." + e.getMessage());
			throw new P2PException(ErrorConst.P2P_S0012);
		}
		finally
		{
			try
			{
				if (output != null)
				{
					output.flush();
					output.close();
				}
				closeConnect(client);
			}
			catch (IOException e)
			{
				throw new P2PException(ErrorConst.P2P_S0012);
			}
		}

		return returnResult;
	}

	public boolean retrieveFile(FTPClient client, String remoteFileName, String localName)
	{
		boolean returnResult = false;

		OutputStream output = null;
		try
		{
			output = new FileOutputStream(localName);
			returnResult = client.retrieveFile(remoteFileName, output);
			if (returnResult)
			{
				logger.info("download success");
			}
			else
			{
				logger.error("download failed");
			}
		}
		catch (FileNotFoundException e)
		{
			logger.error("local file not found." + e.getMessage());
			throw new P2PException(ErrorConst.P2P_S0008);
		}
		catch (IOException e)
		{
			logger.error("Could get file from server." + e.getMessage());
			throw new P2PException(ErrorConst.P2P_S0012);
		}
		finally
		{
			try
			{
				if (output != null)
				{
					output.flush();
					output.close();
				}
			}
			catch (IOException e)
			{
				throw new P2PException(ErrorConst.P2P_S0012);
			}
		}

		return returnResult;
	}

	public void retrieveDirectory(String remoteDirectoryName, String localPath)
	{
		OutputStream output = null;
		try
		{
			boolean flag = client.changeWorkingDirectory(remoteDirectoryName);
			if (!flag)
			{
				logger.error("切换工作目录失败");
				throw new P2PException(ErrorConst.P2P_S0011);
			}

			File dir = new File(localPath);
			if (!dir.exists())
			{
				dir.mkdirs();
			}

			// 处理传输
			FTPFile[] fileList = client.listFiles();
			for (int i = 0; i < fileList.length; i++)
			{
				output = new FileOutputStream(localPath + "/" + fileList[i].getName());
				client.retrieveFile(fileList[i].getName(), output);
				output.flush();
			}
			logger.info("download success");
		}
		catch (FileNotFoundException e)
		{
			logger.error(e.fillInStackTrace().toString());
			logger.error("local file not found." + e.getMessage());
			throw new P2PException(e.getMessage());
		}
		catch (IOException e)
		{
			logger.error(e.fillInStackTrace().toString());
			logger.error("Could get file from server." + e.getMessage());
			throw new P2PException(e.getMessage());
		}
		finally
		{
			try
			{
				if (output != null)
				{
					output.flush();
					output.close();
				}
			}
			catch (Exception e)
			{
				logger.error(e.fillInStackTrace().toString());
			}
		}
	}

	public boolean renameRemoteFile(String remoteFileName, String localPath, String localName)
	{
		boolean flag = true;
		FTPClient client = connectServer();
		try
		{
			client.makeDirectory(localPath);
			flag = client.rename(remoteFileName, localName);
		}
		catch (IOException e)
		{
			flag = false;
			logger.error("Could not rename file from server." + e.getMessage());
			throw new P2PException(ErrorConst.P2P_S0011);
		}
		finally
		{
			closeConnect(client);
		}
		return flag;
	}

	/**
	 * 关闭FTP链接
	 */
	public void closeConnect(FTPClient client)
	{
		try
		{
			if (client != null)
			{
				client.logout();
				client.disconnect();
				logger.info("Ftp closed");
			}
		}
		catch (Exception e)
		{
			logger.error(e.getMessage(), e);
			throw new P2PException(ErrorConst.P2P_S0009);
		}
	}

	/**
	 * 登录FTP服务器 参数:IP,PORT,USER,PASSWORD
	 */
	public FTPClient connectServer()
	{
		int reply;
		FTPClient returnClient = null;
		String configArgs = config;
		String[] args = configArgs.split(",");
		try
		{
			returnClient = new FTPClient();
			returnClient.setControlEncoding("UTF-8");
			returnClient.setDefaultPort(Integer.valueOf(args[1]));
			returnClient.connect(args[0]);
			returnClient.login(args[2], args[3]);
			logger.info(returnClient.getReplyString());
			reply = returnClient.getReplyCode();
			returnClient.setDataTimeout(120000);
			if (!FTPReply.isPositiveCompletion(reply))
			{
				returnClient.disconnect();
				throw new P2PException(ErrorConst.P2P_S0010);
			}
			returnClient.setFileType(BINARY_FILE_TYPE);
			returnClient.enterLocalPassiveMode();
			returnClient.setFileTransferMode(FTP.STREAM_TRANSFER_MODE);
		}
		catch (SocketException e)
		{
			logger.error("登录ftp服务器异常");
			throw new P2PException(ErrorConst.P2P_S0010);
		}
		catch (IOException e)
		{
			logger.error("登录ftp服务器异常");
			throw new P2PException(ErrorConst.P2P_S0010);
		}

		this.client = returnClient;
		return returnClient;
	}

	/**
	 * 
	 * @param dir
	 */
	//使用绝对路径创建目录
	public static boolean makeDirectory(FTPClient client, String dir)
	{
		boolean returnResult = false;

		if (client == null)
			return false;

		dir = StringUtils.replace(dir, File.separator, "/");
		boolean flag = true;
		String[] array = StringUtils.split(dir, "/");
		String tmp = "";
		for (int i = 0; i < array.length; i++)
		{
			tmp = (i == 0 ? "/" : "") + array[i];
			try
			{
				if (!client.changeWorkingDirectory(tmp))
				{
					flag = client.makeDirectory(tmp);
					if (flag && client.changeWorkingDirectory(tmp))
					{
						returnResult = true;
						logger.info("make Directory " + dir + " succeed");
					}
					else
					{
						logger.error("make Directory " + dir + " false");
						throw new P2PException(ErrorConst.P2P_S0013, null, new String[] { dir });
					}
				}
			}
			catch (IOException e)
			{
				throw new P2PException(ErrorConst.P2P_S0013, null, new String[] { dir });
			}
		}

		return returnResult;
	}
}
